export default class AnimateJs {
  constructor(opt) {
    this.cssarr = [];
    this.anm = [];
    this.multp = false;
    // this.animate(el, options, cb);
    this.opt = opt || {};
  }
  execss(epr, i) {
    const name = epr.class;
    const duration = epr.duration;
    const action = epr.action;
    const mode = epr.mode || "none";
    let timing = "linear";
    const ty = {
      v: "transform: translate3d(0, *, 0);", // 下移动
      l: "transform: translate3d(*, 0, 0);", // 左右移动
      p: "transform: translate3d(x, y, 0);", // 点到点移动
      o: "opacity: *;",
      top: "top: *;",
      left: "left: *;",
      r: "transform: rotate(*);", // 旋转
    };
    const ss = [];
    const se = [];
    let soi = "opacity: 0";
    let soo = "opacity: 1";
    Object.keys(action).forEach((k, i) => {
      let s = "";
      let e = "";
      if (k === "p") {
        s = ty[k].replace(/x/g, action[k][0][0]);
        s = s.replace(/y/g, action[k][0][1]);
        e = ty[k].replace(/x/g, action[k][1][0]);
        e = e.replace(/y/g, action[k][1][1]);
      }
      if (k === "o") {
        soi = s;
        soo = e;
      } else {
        if (action[k][2]) {
          timing = action[k][2];
        }
        s = ty[k].replace(/\*/g, action[k][0]);
        e = ty[k].replace(/\*/g, action[k][1]);
        ss.push(s);
        se.push(e);
      }
    });
    this.anm = this.anm.concat([
      {
        name: name + "__" + i,
        duration: duration,
        timing: timing,
        mode: mode,
      },
    ]);
    const n = this.anm.map((r) => r.name).join(", ");
    const d = this.anm.map((r) => r.duration).join(", ");
    const t = this.anm.map((r) => r.timing).join(", ");
    const m = this.anm.map((r) => r.mode).join(", ");
    this.ani = `.${name}{animation-name: ${n};animation-duration: ${d};animation-timing-function: ${t}; animation-fill-mode: ${m};}`;
    console.log(this.ani, "--this.anm--");
    const text =
      "@keyframes " +
      name +
      "__" +
      i +
      " {" +
      "from {" +
      soi +
      ";" +
      ss.join(" ") +
      "}" +
      "to {" +
      soo +
      ";" +
      se.join(" ") +
      "}" +
      "}";

    if (this.multp && i === 0) {
      this.ani = "";
    }
    const hty = document.querySelector("style[animate='cyi__"+ name +"']");
    console.log("shty", this.cssarr)
    if (!this.cssarr.includes(this.ani + text)) {
      this.cssarr = this.cssarr.concat(this.ani + text);
    }
    if (!hty) {
      const sty = document.createElement("style");
      sty.innerHTML = this.cssarr.join("");
      sty.setAttribute("animate", "cyi__" + name);
      sty.setAttribute("type", "text/css");
      document.head.append(sty);
    } else {
      hty.innerHTML = this.cssarr.join("");
    }
  }
  removeStyle(el) {
    const style = el.getAttribute("style");
    if (style) {
      const sty = style.replace(
        /--animate-duration:\s?\d+(.\d+)?s;|\s?animation-fill-mode:\s+[a-z]+;/g,
        ""
      );
      el.style.cssText = sty;
    }
  }

  removeEl(el) {
    el.parentNode.removeChild(el);
  }

  stop(el) {
    el.style.setProperty("--animate-duration", "0s");
  }
  animateEnd(el, cb) {
    const fn = () => {
      el.removeEventListener("animationend", fn);
      if (this.step < this.max && this.autoNext) {
        setTimeout(() => {
          this.step++;
          this.play();
          cb();
          this.open = true;
        }, 300);
      } else {
        setTimeout(() => {
          cb();
          this.open = true;
        }, 300);
      }
    };
    el.addEventListener("animationend", fn);
  }
  getOpts(agr) {
    const all = agr instanceof Array ? agr : [agr];
    let o = {};
    let max = 0;
    return new Promise((resolve) => {
      all.forEach((a, i) => {
        const x = a.duration.replace(/[msh]/gi, "") * 1;
        if (x > max) {
          max = x;
          o = a;
        }
        if (a.action.q && a.action.q.x && a.action.q.y) {
          const x = a.action.q.x;
          const y = a.action.q.y;
          const b = Object.assign({}, a);
          b.action.left = x;
          const c = Object.assign({}, a);
          c.action.top = y;
          this.multp = true;
          delete b.action.q;
          delete c.action.q;
          this.execss(b, 0);
          this.execss(c, 1);
        } else {
          this.execss(a, 0);
        }
        if (i === all.length - 1) {
          resolve(o);
        }
      });
    });
  }
  async animate(el, agr, cb) {
    el = this.opt.isClone ? this.cloneNode(el) : el;
    const options = await this.getOpts(agr);
    const name = options.class;
    const duration = options.duration;
    const mode = options.mode || "none";
    const css = el.className;
    setTimeout(() => {
      this.stop(el);
      if (el.className.indexOf(name) === -1) {
        el.style.setProperty("--animate-duration", duration);
        el.style.setProperty("animation-fill-mode", mode);
        el.className += " " + name;
      }
      this.animateEnd(el, () => {
        if (mode === "none") {
          el.className = css;
          this.removeStyle(el);
          if (this.opt.isClone) {
            this.removeEl(el);
          }
        }
        if (cb) {
          cb(el);
        }
      });
    }, 60);
  }
  cloneNode(el) {
    const top = el.offsetTop;
    const left = el.offsetLeft;
    const node = el.cloneNode(true);
    node.style.cssText = `${node.style.cssText}position: absolute;top: ${top}px;left: ${left}px;z-index:9;`;
    el.parentNode.appendChild(node);
    return node;
  }
}
